/*
* Copyright 2017 LinkedIn Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package azkaban.db;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.log4j.Logger;
public class MySQLDataSource extends AzkabanDataSource {
private static Logger logger = Logger.getLogger(MySQLDataSource.class);
private static volatile MySQLDataSource instance = null;
// TODO kunkun-tang: have guice inject working here
private MySQLDataSource(String host, int port, String dbName,
String user, String password, int numConnections) {
super();
String url = "jdbc:mysql://" + (host + ":" + port + "/" + dbName);
addConnectionProperty("useUnicode", "yes");
addConnectionProperty("characterEncoding", "UTF-8");
setDriverClassName("com.mysql.jdbc.Driver");
setUsername(user);
setPassword(password);
setUrl(url);
setMaxTotal(numConnections);
setValidationQuery("/* ping */ select 1");
setTestOnBorrow(true);
}
/**
* Get a singleton object for MySQL BasicDataSource
*/
public static MySQLDataSource getInstance(String host, int port, String dbName,
String user, String password, int numConnections) {
if (instance == null) {
synchronized (MySQLDataSource.class) {
if (instance == null) {
logger.info("Instantiating MetricReportManager");
instance = new MySQLDataSource(host, port, dbName, user, password, numConnections);
}
}
}
return instance;
}
/**
* This method overrides {@link BasicDataSource#getConnection()}, in order to have retry logics.
*
*/
@Override
public synchronized Connection getConnection() throws SQLException {
Connection connection = null;
int retryAttempt = 0;
while (retryAttempt < AzDBUtil.MAX_DB_RETRY_COUNT) {
try {
/**
* when DB connection could not be fetched (e.g., network issue), or connection can not be validated,
* {@link BasicDataSource} throws a SQL Exception. {@link BasicDataSource#dataSource} will be reset to null.
* createDataSource() will create a new dataSource.
* Every Attempt generates a thread-hanging-time, about 75 seconds, which is hard coded, and can not be changed.
*/
connection = createDataSource().getConnection();
if(connection != null)
return connection;
} catch (SQLException ex) {
logger.error("Failed to find DB connection. waits 1 minutes and retry. No.Attempt = " + retryAttempt, ex);
} finally {
retryAttempt ++;
}
}
return null;
}
@Override
public String getDBType() {
return "mysql";
}
}